package com.ruoyi.web.controller.app;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.protobuf.util.JsonFormat;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtil;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.config.AppThirdConfig;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.third.douyin.model.Code2SessionRequest;
import com.ruoyi.system.third.douyin.model.Code2SessionResponse;
import com.ruoyi.system.third.douyin.model.Login;
import com.ruoyi.system.third.douyin.store.Store;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.security.PermitAll;
import java.net.URL;
import java.util.*;

/**
 * 登录验证
 * 
 * @author ruoyi
 */
@RestController
@RequestMapping("/app")
public class AppLoginController
{
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    AppThirdConfig appThirdConfig;

    /**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PermitAll
    @PostMapping("/login")
    public AjaxResult login(@RequestBody String requestBody)
    {
        try {
            // 请求体初始化pb结构
            Login.LoginRequest.Builder requestBuild = Login.LoginRequest.newBuilder();
            JsonFormat.parser().merge(requestBody, requestBuild);
            Login.LoginRequest request = requestBuild.build();

            // 装配code2session请求体
            Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
            Code2SessionRequest code2SessionRequest = new Code2SessionRequest();
            code2SessionRequest.setCode(request.getCode());
            code2SessionRequest.setAppid(appThirdConfig.douyinAppid);
            code2SessionRequest.setSecret(appThirdConfig.douyinSecret);

            // code2session的http请求 TODO 常量化
            String domain = appThirdConfig.douyinDomain;
            if (appThirdConfig.IsSandBox.equals("1")) {
                domain = "open-sandbox.douyin.com";
            }
            String code2SessionPath = "/api/apps/v2/jscode2session";
            Code2SessionResponse response = HttpUtil.HttpPost(code2SessionPath, gson.toJson(code2SessionRequest), "https", domain, Code2SessionResponse.class);

            // 初始化登录返回数据 并处理返回异常
            Login.LoginResponse.Builder builder = Login.LoginResponse.newBuilder();

            // 对返回数据异常处理
            if (response == null || response.getData() == null) {
                builder.setErrCode(-1);
                builder.setErrMsg("error");
                Login.LoginResponse obj = builder.build();
                return AjaxResult.error("登陆失败",obj);
            }
            if (response.getErrNo() != 0) {
                builder.setErrCode(-1);
                builder.setErrMsg(response.getErrTips());
                Login.LoginResponse obj = builder.build();
                return AjaxResult.success(obj);
            }

            // 返回成功则组装返回结构体
            builder.setErrCode(response.getErrNo());
            builder.setErrMsg("");
            builder.setErrCode(0);

            String token = Store.SetCache("", response.getData().getOpenid(), response.getData().getUnionId(), "", response.getData().getSessionKey());
            builder.setToken(token);

            builder.setOpenid(response.getData().getOpenid().substring(0, 3) + "****" + response.getData().getOpenid().substring(7));
            builder.setUnionid(response.getData().getUnionId().substring(0, 3) + "****" + response.getData().getUnionId().substring(7));

            Login.LoginResponse responseBody = builder.build();
            String openid = responseBody.getOpenid();
            String unionid = responseBody.getUnionid();


            AjaxResult ajax = AjaxResult.success();
            // 生成令牌
            String tokenMy = loginService.login(responseBody);
            ajax.put(Constants.TOKEN, tokenMy);
            return ajax;
        }catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    @GetMapping("/getInfo")
    public AjaxResult getInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        return ajax;
    }

    /**
     * 获取路由信息
     * 
     * @return 路由信息
     */
    @GetMapping("/getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }
    
    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate)
    {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0)
        {
            if (StringUtils.isNull(pwdUpdateDate))
            {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }


    @PostMapping("/getFile")
    @Operation(summary = "获取文件", description = "模式一：获取文件")
    public AjaxResult getFile(@RequestParam("fileName") String fileName) throws Exception {
       return AjaxResult.success();
    }
}
